package network_programming.np1_socket_and_serversocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 关闭服务器
 * */
public class EchoServerExecutorShutdown {
    private int port = 9099;        // 监听的端口号
    private final ServerSocket serverSocket;
    private ExecutorService executorService;    // 线程池
    private final int POOL_SIZE = 4;    // 单个CUP时线程池中工作线程的数目

    private int portForShutdown = 9100;     // 用于监听关闭服务器命令的端口
    private ServerSocket serverSocketForShutdown;
    private boolean isShutdown = false;     // 服务器是否已经关闭

    private Thread shutdownThread = new Thread(){
        public void run() {
            while (!isShutdown) {
                try (Socket socketForShutdown = serverSocketForShutdown.accept()) {
                    BufferedReader br = new BufferedReader(new InputStreamReader(
                            socketForShutdown.getInputStream()));
                    String command = br.readLine();
                    if (command.equals("shutdown")) {
                        long beginTime = System.currentTimeMillis();
                        socketForShutdown.getOutputStream().write("服务器正在关闭\r\n".getBytes());
                        isShutdown = true;
                        executorService.shutdown(); // 请求关闭线程池
                                                    // 线程池不再接收新的任务，但会继续执行完工作队列中现有的任务
                        while (!executorService.isTerminated()) {   // 等待关闭线程池，每次等待的超时时间为30s
                            executorService.awaitTermination(30, TimeUnit.SECONDS);
                            serverSocket.close();   // 关闭与客户端通信的ServerSocket
                            long endTime = System.currentTimeMillis();
                            socketForShutdown.getOutputStream().write(("服务器已关闭，耗时" +
                                    (endTime - beginTime) + "ms\r\n").getBytes());
                            System.out.println("服务器关闭");
                        }
                    }
                    else
                        socketForShutdown.getOutputStream().write("命令错误\r\n".getBytes());
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    public EchoServerExecutorShutdown() throws IOException {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(60000);   // 设置等待客户连接超时时间为60s
        serverSocketForShutdown = new ServerSocket(portForShutdown);
        executorService = Executors.newFixedThreadPool(
                Runtime.getRuntime().availableProcessors() * POOL_SIZE);
        shutdownThread.start();     // 启动负责关闭服务器的线程
        System.out.println("服务器已启动");
    }

    public void service() {
        while(!isShutdown) {
            try {
                Socket socket = serverSocket.accept();
                socket.setSoTimeout(60000); // 设置等待客户发送数据的超时时间为60s
                executorService.execute(new EchoServerHandler(socket));		// 把与客户通信的任务交给线程池
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new EchoServerExecutorShutdown().service();
    }
}
